"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;
/**
 * 树节点
 */
class TreeNode {
  origin;
  childNodes = [];
  tree;
  parent;
  uniqueKey = 'key';
  childrenKey = 'children';
  constructor(data, options) {
    this.origin = data;
    if (options.uniqueKey) this.uniqueKey = options.uniqueKey;
    if (options.childrenKey) this.childrenKey = options.childrenKey;
    if (options.parent) this.parent = options.parent;
    if (!options.tree) {
      console.error('options.tree cannnot be undefined');
    }
    this.tree = options.tree;
    (data[this.childrenKey] ?? []).forEach(child => {
      const childNode = new TreeNode(child, {
        uniqueKey: this.uniqueKey,
        childrenKey: this.childrenKey,
        parent: this,
        tree: this.tree
      });
      this.childNodes.push(childNode);
    });

    /**
     * @todo 暂时不用 Proxy 代理，第一导致调试不方便，第二会导致测试用例不通过，需要改造
     * 使用 Proxy 代理支持访问原始数据属性
     */
    // return new Proxy(this, {
    //   get(target, propKey) {
    //     if (propKey in target) return target[propKey];
    //     return target.origin[propKey];
    //   },
    // });
  }

  /** 获取属性 */
  getProperty(propertyKey) {
    return this.origin[propertyKey];
  }

  /** 设置属性 */
  setProperty(propertyKey, propertyValue) {
    return this.origin[propertyKey] = propertyValue;
  }

  /** @todo 暂时使用 get 直接获取视图渲染数据 */
  get title() {
    return this.getProperty('title');
  }

  /** @todo 暂时使用 get 直接获取视图渲染数据 */
  get label() {
    return this.getProperty('label');
  }

  /** @todo 暂时使用 get 直接获取视图渲染数据 */
  get value() {
    return this.getProperty('value');
  }

  /** @todo 暂时每次访问均使用新的引用，以使视图更新 */
  get children() {
    return [...this.childNodes];
  }

  /** 节点唯一标识 */
  get key() {
    return this.origin[this.uniqueKey];
  }

  /** 父节点唯一标识 */
  get parentKey() {
    return this.parent?.origin?.[this.uniqueKey];
  }

  /** 节点路径 */
  get nodePath() {
    const result = [];
    let curr = this;
    while (curr) {
      result.unshift(curr);
      curr = curr.parent;
    }
    return result;
  }

  /** 从 1 开始计数 */
  get level() {
    return this.nodePath.length;
  }

  /** 包含自身的兄弟节点 */
  get siblingsIncludeSelf() {
    return !this.parent ? this.tree.nodes : this.parent?.childNodes;
  }

  /** 去除自身的兄弟节点 */
  get siblings() {
    return this.siblingsIncludeSelf?.filter(it => it !== this);
  }

  /** 索引 */
  get index() {
    return this.siblingsIncludeSelf ? this.siblingsIncludeSelf?.indexOf(this) : -1;
  }

  /** 是否可能叶子节点，不适用于懒加载情况 */
  get isMaybeLeaf() {
    return !this.childNodes?.length;
  }

  /** 遍历 */
  forEach(iteratee, options = {
    mode: 'pre'
  }) {
    const mode = options.mode;
    if (mode === 'post') {
      this.childNodes.forEach(childNode => {
        childNode.forEach(iteratee, options);
      });
      iteratee(this);
    } else {
      iteratee(this);
      this.childNodes.forEach(childNode => childNode.forEach(iteratee));
    }
  }

  /** 过滤 */
  filter(predicate, options = {
    mode: 'pre',
    isTree: false
  }) {
    let result = [];
    const {
      mode,
      isTree
    } = options;
    if (isTree) {
      // 此方法会更改节点的 childNodes
      // 返回符合过滤条件的根节点
      function postTraverse(curr) {
        const matchedChildren = [];
        curr.childNodes.forEach((childNode, i) => {
          postTraverse(childNode);
          if (childNode.childNodes?.length || predicate(childNode)) matchedChildren.push(childNode);
          if (i === curr.childNodes.length - 1) {
            curr.childNodes = matchedChildren;
          }
        });
      }
      postTraverse(this);
      if (this.childNodes?.length || predicate(this)) result.push(this);
      return result;
    }
    if (mode === 'post') {
      this.childNodes.forEach(childNode => {
        const res = childNode.filter(predicate, options);
        result.push(...res);
      });
      if (predicate(this)) result.push(this);
    } else {
      if (predicate(this)) result.push(this);
      this.childNodes.forEach(childNode => {
        const filtered = childNode.filter(predicate);
        result = result.concat(filtered);
      });
    }
    return result;
  }

  /** 遍历 */
  map(convert) {
    let result = [];
    result.push(convert(this));
    this.childNodes.forEach(childNode => {
      const converted = childNode.map(convert);
      result = result.concat(converted);
    });
    return result;
  }

  /** 转数组 */
  toArray() {
    return this.map(node => node);
  }

  /** 转键值对映射 */
  toMap() {
    const result = {};
    this.forEach(node => {
      result[node.key] = node;
    });
    return result;
  }

  /** 从当前节点及其子孙节点中判断是否包含 */
  has(predicate) {
    const realPredicate = typeof predicate === 'string' ? node => node.key === predicate : predicate;
    if (realPredicate(this)) return true;
    return this.childNodes.some(childNode => childNode.has(realPredicate));
  }

  /** 通过匹配规则从当前节点及其子孙节点中查找 */
  query(predicate) {
    const realPredicate = typeof predicate === 'string' ? node => node.key === predicate : predicate;
    if (realPredicate(this)) return this;
    let result;
    this.childNodes.some(childNode => {
      const found = childNode.query(realPredicate);
      if (found) {
        result = found;
        return true;
      }
    });
    return result;
  }

  /**
   * 尾部添加子节点（不改变原始数据）
   */
  append(data) {
    if (this.tree.has(data[this.uniqueKey])) {
      throw new Error(`${data[this.uniqueKey]} is existed already`);
    }
    const node = new TreeNode(data, {
      uniqueKey: this.uniqueKey,
      childrenKey: this.childrenKey,
      parent: this,
      tree: this.tree
    });
    this.childNodes.push(node);
    return this;
  }

  /**
   * 尾部添加子节点列表（不改变原始数据）
   */
  appendChildren(datas) {
    datas.forEach(data => {
      if (this.tree.has(data[this.uniqueKey])) {
        throw new Error(`${data[this.uniqueKey]} is existed already`);
      }
    });
    datas.forEach(data => {
      const node = new TreeNode(data, {
        uniqueKey: this.uniqueKey,
        childrenKey: this.childrenKey,
        parent: this,
        tree: this.tree
      });
      this.childNodes.push(node);
    });
    return this;
  }

  /**
   * 头部添加子节点（不改变原始数据）
   */
  prepend(data) {
    if (this.tree.has(data[this.uniqueKey])) {
      throw new Error(`${data[this.uniqueKey]} is existed already`);
    }
    const node = new TreeNode(data, {
      uniqueKey: this.uniqueKey,
      childrenKey: this.childrenKey,
      parent: this,
      tree: this.tree
    });
    this.childNodes.unshift(node);
    return this;
  }

  /**
   * 头部添加子节点列表（不改变原始数据）
   */
  prependChildren(datas) {
    datas.forEach(data => {
      if (this.tree.has(data[this.uniqueKey])) {
        throw new Error(`${data[this.uniqueKey]} is existed already`);
      }
    });
    datas.reverse().forEach(data => {
      const node = new TreeNode(data, {
        uniqueKey: this.uniqueKey,
        childrenKey: this.childrenKey,
        parent: this,
        tree: this.tree
      });
      this.childNodes.unshift(node);
    });
    return this;
  }

  /** 当前节点后插入（不改变原始数据） */
  after(data) {
    const node = new TreeNode(data, {
      uniqueKey: this.uniqueKey,
      childrenKey: this.childrenKey,
      parent: this.parent,
      tree: this.tree
    });
    if (!this.parent) {
      this.tree.nodes.splice(this.index + 1, 0, node);
    } else {
      this.parent.childNodes.splice(this.index + 1, 0, node);
    }
    return this;
  }

  /** 当前节点前插入（不改变原始数据） */
  before(data) {
    const node = new TreeNode(data, {
      uniqueKey: this.uniqueKey,
      childrenKey: this.childrenKey,
      parent: this.parent,
      tree: this.tree
    });
    if (!this.parent) {
      this.tree.nodes.splice(this.index, 0, node);
    } else {
      this.parent.childNodes.splice(this.index, 0, node);
    }
    return this;
  }

  /** 替换节点 */
  replaceWith(data) {
    const node = new TreeNode(data, {
      uniqueKey: this.uniqueKey,
      childrenKey: this.childrenKey,
      parent: this.parent,
      tree: this.tree
    });
    if (!this.parent) {
      this.tree.nodes.splice(this.index, 1, node);
    } else {
      this.parent?.childNodes.splice(this.index, 1, node);
    }
    return this;
  }

  /** 删除节点，不会改变当前节点的父节点指向（不改变原始数据） */
  remove() {
    if (!this.parent) {
      this.tree.nodes.splice(this.index, 1);
    } else {
      this.parent?.childNodes.splice(this.index, 1);
    }
    return this;
  }
}
var _default = exports.default = TreeNode;